﻿#ifndef __SBDEF_H__
#define __SBDEF_H__

#if _MSC_VER
#pragma once
#endif

#include <stdint.h>
#include <wchar.h>
#include "sbconf.h"

#if _SB_LINUX_
#include <linux/limits.h>
#endif

//////////////////////////////////////////////////////////////////////////
// api
#ifndef KAPI
#	ifdef _STATIC
#		define KAPI						extern
#	else
#		if _SB_WINDOWS_
#			define KAPI					__declspec(dllimport)
#		elif __GNUC__
#			define KAPI					__attribute__((__visibility__("default")))
#		else
#			define KAPI					extern
#		endif
#	endif
#endif


//////////////////////////////////////////////////////////////////////////
// compiler decision
#if _MSC_VER
#	define K_ALIGN(x)					__declspec(align(x))
#	define K_FORCEINLINE				__forceinline
#	define K_INLINE						__inline
#	define K_CALL						__stdcall
#	define K_WINAPI						__stdcall
#if defined(__cplusplus)
#	define K_NOTHROW					__declspec(nothrow)
#else
#	define K_NOTHROW
#endif
#	define K_SELECTANY					__declspec(selectany)
#elif __GNUC__
#	define K_ALIGN(x)					__attribute__ ((aligned(x)))
#ifndef __cplusplus
#	define K_FORCEINLINE				static inline __attribute__ ((always_inline))
#	define K_INLINE						static inline
#else
#	define K_FORCEINLINE				inline __attribute__ ((always_inline))
#	define K_INLINE						inline
#endif
#if _SB_WINDOWS_
#	define K_CALL						__cdecl
#	define K_WINAPI						__stdcall
#else
#	define K_CALL
#	define K_WINAPI
#endif
#if defined(__cplusplus)
#	define K_NOTHROW					__attribute__ ((nothrow))
#else
#	define K_NOTHROW
#endif
#	define K_SELECTANY					/*__attribute__ ((selectany))*/
#else
#	define K_ALIGN(x)
#ifndef __cplusplus
#	define K_FORCEINLINE				static inline
#	define K_INLINE						static inline
#else
#	define K_FORCEINLINE				inline
#	define K_INLINE						inline
#endif
#	define K_CALL
#	define K_WINAPI
#	define K_NOTHROW
#	define K_SELECTANY
#endif

#if _MSC_VER
#	define K_FUNCNAME					__FUNCTION__
#elif _SB_C99_
#	define K_FUNCNAME					__func__
#elif __GNUC__
#	define K_FUNCNAME					__PRETTY_FUNCTION__
#else
#	define K_FUNCNAME					"<unknown>"
#endif

#if defined(__cplusplus)
#	define K_EXTERN_C					extern "C"
#	define K_EXTERN_C_BEGIN				extern "C" {
#	define K_EXTERN_C_END				}
#	define K_OVR						virtual
#	ifdef __GNUC__
#		define K_VPL					virtual
#	else
#		define K_VPL
#	endif
#else
#	define K_EXTERN_C
#	define K_EXTERN_C_BEGIN
#	define K_EXTERN_C_END
#	define K_OVR							
#	define K_VPL							
#endif


//////////////////////////////////////////////////////////////////////////
// compond
#define K_STMT_BEGIN					do
#define K_STMT_END						while(0)


//////////////////////////////////////////////////////////////////////////
// string & array & structure && etc
#if _SB_WINDOWS_
#	define K_PATH_SEP					'\\'
#else
#	define K_PATH_SEP					'/'
#endif

#define K_CONCAT_0(x,y)					x##y
#define K_CONCAT_1(x,y)					K_CONCAT_0(x,y)
#define K_CONCAT_2(x,y)					K_CONCAT_1(x,y)
#define K_CONCAT(x,y)					K_CONCAT_0(x,y)

#define K_CONTRI_0(x,y,z)				x##y##z
#define K_CONTRI_1(x,y,z)				K_CONTRI_0(x,y,z)
#define K_CONTRI_2(x,y,z)				K_CONTRI_1(x,y,z)
#define K_CONTRI(x,y,z)					K_CONTRI_0(x,y,z)

#define K_STRING_0(x)					#x
#define K_STRING_1(x)					K_STRING_0(x)
#define K_STRING(x)						K_STRING_0(x)

#define K_L_0(x)						L##x
#define K_L_1(x)						K_L_0(x)
#define K_L(x)							K_L_0(x)

#define K_COUNTOF(arr)					(sizeof(arr)/sizeof(arr[0]))							/** 매크로: 정적 배열의 크기를 얻는다 */
#define K_OFFSETOF(type,mem)			((ksize_t)((kchar*)&((type*)0)->mem))					/** 매크로: 구조체 멤버의 옵셋을 얻는다 */
#define K_MEMBEROF(type,p,off)			(*(type*)((kpointer)((kchar*)(p)+(ksize_t)(offset))))	/** 매크로: 구조체 멤버의 위치를 얻는다 */

#define K_BIT(n)						(1<<n)													/** 매크로: 지정한 비트필드값을 만든다 */

#if defined(__cplusplus)
#	define K_P(x)						= x
#else
#	define K_P(x)
#endif
#define K_P_(x)

#define KCALL							K_NOTHROW K_CALL

#define K_UNSAFE
#define K_UNSAFE_NTH
#define K_UNSAFE_RET
#define K_UNSAFE_ARG


//////////////////////////////////////////////////////////////////////////
// compatible basic
#define K_MAX(a,b)						(((a)>(b)) ? (a) : (b))
#define K_MIN(a,b)						(((a)<(b)) ? (a) : (b))
#define K_ABS(v)						(((v)<0) ? -(v) : (v))
#define K_CLAMP(v,min,max)				((v)<(min) ? (min) : (v)>(max) ? (max) : (v))

#define K_NOUSE(v)						(void)(v)
#define K_MAKEWORD(low,high)			((kushort)(((kbyte)(low)) | ((kushort)((kbyte)(high))) << 8))
#define K_MAKEDWORD(a,b,c,d)			((kuint)(((kuint)(kbyte)(a)<<24) | ((kuint)(kbyte)(b)<<16) | ((kuint)(kbyte)(c)<<8) | (kuint)(kbyte)(d)))
#define K_MAKEFOURCC(a,b,c,d)			((kuint)(kbyte)(a) | ((kuint)(kbyte)(b) <<8 ) | ((kuint)(kbyte)(c) << 16) | ((kuint)(kbyte)(d) << 24))
#if _SB_BIGENDIAN_
#define K_MAKECOLOR(a,r,g,b)			((kuint)(((kuint)(kbyte)(b)<<24) | ((kuint)(kbyte)(g)<<16) | ((kuint)(kbyte)(r)<<8) | (kuint)(kbyte)(a)))
#else
#define K_MAKECOLOR(a,r,g,b)			((kuint)(((kuint)(kbyte)(a)<<24) | ((kuint)(kbyte)(r)<<16) | ((kuint)(kbyte)(g)<<8) | (kuint)(kbyte)(b)))
#endif

#define K_OMASK(v,m)					((m) == 0 ? (v) : (v)&(m))
#define K_OFLAG(v,m)					(((v)&(m))!=0)									// open flag
#define K_UFLAG(pv,m,e)					((e) ? ((*(pv))|=(m)) : ((*(pv))&=~(m)))		// unite flag, do not use on bitfiled
#define K_YFLAG(v,m,e)					((e) ? ((v)|=(m)) : ((v)&=~(m)))				// yet another unite flag, can use bitfield. but, only internal


//////////////////////////////////////////////////////////////////////////
// cast & conversion & range
#define K_CAST_PTR_TO_INT(v)			((kint)(kuintptr)(v))
#define K_CAST_PTR_TO_UINT(v)			((kuint)(kuintptr)(v))
#define K_CAST_PTR_TO_SIZE(v)			((ksize_t)(v))
#define K_CAST_PTR_TO_FLOAT(v)			(*(float*)&(v))
#define K_CAST_PTR_TO_PINT(v)			((kintptr)(v))
#define K_CAST_PTR_TO_PUINT(v)			((kuintptr)(v))
#define K_CAST_INT_TO_PTR(v)			((kpointer)(kuintptr)(v))
#define K_CAST_INT_TO_UINT(v)			((kuint)(v))
#define K_CAST_INT_TO_FLOAT(v)			(*(float*)&(v))
#define K_CAST_UINT_TO_PTR(v)			((kpointer)(kuintptr)(v))
#define K_CAST_UINT_TO_INT(v)			(*(kint*)&(v))
#define K_CAST_UINT_TO_FLOAT(v)			(*(float*)&(v))
#define K_CAST_FLOAT_TO_PTR(v)			(*(kpointer*)&(v))
#define K_CAST_FLOAT_TO_UINT(v)			(*(kuint*)&(v))
#define K_CAST_FLOAT_TO_INT(v)			(*(kint*)&(v))
#define K_CAST_PINT_TO_PTR(v)			((kpointer)(kuintptr)(v))
#define K_CAST_PUINT_TO_PTR(v)			((kpointer)(kuintptr)(v))
#define K_CAST_SIZE_TO_PTR(v)			((kpointer)(v))
#define K_CAST_SEC_TO_MSEC(v)			((v)*1000000)
#define K_CAST_SEC_TO_MILLI(v)			((v)*1000)
#define K_CAST_SIZEOF_TO_PTR(type)		((kpointer)(sizeof(type)))
#define K_CAST_PTR_TO_TYPE(v,type)		((type*)(v))

#if __GNUC__
#define K_CAST_ENUM(x)					(ksize_t)(x)
#define K_CAST_UNION_TYPE(x)			(x)
#else
#define K_CAST_ENUM(x)					x
#define K_CAST_UNION_TYPE(x)
#endif

#define K_MIN_HASH						11
#define K_MAX_HASH						13845163
#define K_MAX_RAND						0x7FFF

#define K_MIN_SBYTE						((ksbyte)0x80)
#define K_MAX_SBYTE						((ksbyte)0x7F)
#define K_MAX_BYTE						((kbyte) 0xFF)

#define K_MIN_SHORT						((kshort) 0x8000)
#define K_MAX_SHORT						((kshort) 0x7FFF)
#define K_MAX_USHORT					((kushort)0xFFFF)

#define K_MIN_INT						((kint) 0x80000000)
#define K_MAX_INT						((kint) 0x7FFFFFFF)
#define K_MAX_UINT						((kuint)0xFFFFFFFF)

#define K_MIN_LONG						((klong) K_CONST_LONG(0x8000000000000000))
#define K_MAX_LONG						((klong) K_CONST_LONG(0x7FFFFFFFFFFFFFFF))
#define K_MAX_ULONG						((kulong)K_CONST_ULONG(0xFFFFFFFFFFFFFFFF))

#define K_IEEE754_FLOAT_BIAS			127
#define K_IEEE754_DOUBLE_BIAS			1023

#define K_INVALID_VALUE					(-1)
#define K_INVALID_SIZE					((ksize_t)K_INVALID_VALUE)
#define K_INVALID_POINTER				((kpointer)(kuintptr)K_INVALID_VALUE)
#define K_MASK_VALUE					(0xFFFFFFFF)

#if _MSC_VER
#define K_CONST_LONG(n)					(n##i64)
#define K_CONST_ULONG(n)				(n##Ui64)
#else
#define K_CONST_LONG(n)					(n##LL)
#define K_CONST_ULONG(n)				(n##ULL)
#endif

#define K_CONST_EPSILON					0.0001
#define K_CONST_E						2.7182818284590452353602874713526624977572470937000
#define K_CONST_LOG2E					1.44269504088896340736
#define K_CONST_LOG10E					0.434294481903251827651
#define K_CONST_LOG2B10					0.30102999566398119521
#define K_CONST_LN2						0.6931471805599453094172321214581765680755001343603
#define K_CONST_LN10					2.3025850929940456840179914546843642076011014886288
#define K_CONST_PI						3.1415926535897932384626433832795028841971693993751
#define K_CONST_PI2						6.2831853071795864769252867665590057683943387987502
#define K_CONST_PI_2					1.5707963267948966192313216916397514420985846996876
#define K_CONST_PI_4					0.7853981633974483096156608458198757210492923498438
#define K_CONST_SQRT2					1.4142135623730950488016887242096980785696718753769
#define K_CONST_SQRT1_2					0.7071067811865475244008443621048490392848359376884

#define K_CONST_USEC_PER_SEC			1000000
#define K_CONST_NSEC_PER_SEC			1000000000

#ifdef PATH_MAX
#define K_MAX_PATH						PATH_MAX
#else
#define K_MAX_PATH						260
#endif

#if _MSC_VER
#define K_ANY_CONST						extern const K_SELECTANY
#else
#define K_ANY_CONST						static const
#endif


//////////////////////////////////////////////////////////////////////////
// types

// basic
typedef void							kvoid;
typedef char							kchar;
typedef wchar_t							kwchar;
typedef int32_t							kcham;

// signed
typedef int8_t							ksbyte;
typedef int16_t							kshort;
typedef int32_t							kint;
typedef int64_t							klong;

// unsigned
typedef uint8_t							kbyte;
typedef uint16_t						kushort;
typedef uint32_t						kuint;
typedef uint64_t						kulong;

// float
typedef float							kfloat;
typedef double							kdouble;

// pointer
typedef void*							kpointer;
typedef const void*						kconstpointer;
typedef void const*						kpointerconst;

// handle
typedef void*							khandle;

// system length
typedef intptr_t						kintptr;
typedef uintptr_t						kuintptr;

// size
typedef intptr_t						kssize_t;
typedef uintptr_t						ksize_t;

// unicode
#if _MSC_VER
typedef kuint							kucs4char;
typedef kwchar							kucs2char;
#elif _SB_UNIX_
typedef kwchar							kucs4char;
typedef kushort							kucs2char;
#else
typedef kuint							kucs4char;
typedef kushort							kucs2char;
#endif

// bool
#if defined(_SB_CPP_)
typedef bool							kbool;
#elif defined(_SB_C99_)
typedef _Bool							kbool;
#else
typedef ksbyte							kbool;
#endif

// external
typedef kushort							khalf;

// function
typedef void (*kfunc)();
typedef void (*kfunc_1)(kpointer);
typedef void (*kfunc_2)(kpointer, kpointer);
typedef void (*kfunc_3)(kpointer, kpointer, kpointer);

// internal alias
#define kint8							ksbyte
#define kint16							kshort
#define kint32							kint
#define kint64							klong

#define kuint8							kbyte
#define kuint16							kushort
#define kuint32							kuint
#define kuint64							kulong

#define kvint16							kvshort
#define kvint32							kvint
#define kvint64							kvlong


//////////////////////////////////////////////////////////////////////////
// IEE754

/** 32비트 단정도 실수. */
typedef union kfloatIEEE754
{
	kfloat				v;
	struct 
	{
		kuint			manissa		: 23;
		kuint			exponent	: 8;
		kuint			sign		: 1;
	} mpn;
} kfloatIEEE754;

/** 64비트 배정도 실수. */
typedef union kdoubleIEEE754
{
	kdouble				v;
	struct
	{
		kuint			low			: 32;
		kuint			high		: 20;
		kuint			exponent	: 11;
		kuint			sign		: 1;
	} mpn;
} kdoubleIEEE754;


//////////////////////////////////////////////////////////////////////////
// var type

/** 가변 16비트 정수. */
typedef union kvshort
{
	struct 
	{
		kbyte			l, h;
	} b;
	kushort				w;
} kvshort;

/** 가변 32비트 정수. */
typedef union kvint
{
	struct 
	{
		kbyte			a, b, c, d; // d=msb
	} b;
	struct  
	{
		kushort			l, h;
	} w;
	kuint				dw;
} kvint;

/** 가변 64비트 정수. */
typedef union kvlong
{
	struct
	{
		kbyte			la, lb, lc, ld;
		kbyte			ha, hb, hc, hd; // hd=msb
	} b;
	struct 
	{
		kushort			a, b, c, d;
	} w;
	struct 
	{
		kuint			l, h;
	} dw;
	kulong				q;
} kvlong;


//////////////////////////////////////////////////////////////////////////
// any type

/** 아무 값이나 넣는 형식. */
typedef union kany
{
	kbool				b;
	kcham				m;
	kint				i;
	kuint				u;
	kfloat				f;

	kchar*				s;
	kwchar*				w;
	kpointer			p;
	kconstpointer		cp;
	kfunc				func;

#if _SB_64_	
	klong				i64;
	kulong				u64;
	kdouble				dbl;

	kbyte				data[8];
#else
	kbyte				data[4];
#endif
} kany;

/** 최대 64비트의 아무 값이나 넣는 형식. */
typedef union kany64
{
	kbool				b;
	kcham				m;
	kint				i;
	kuint				u;
	kfloat				f;

	kchar*				s;
	kwchar*				w;
	kpointer			p;
	kconstpointer		cp;
	kfunc				func;

	ksbyte				i8;
	kshort				i16;
	kint				i32;
	klong				i64;

	kbyte				u8;
	kushort				u16;
	kuint				u32;
	kulong				u64;

	kdouble				dbl;

	kbyte				data[8];
} kany64;

/** 포인터를 통한 아무 값이나 넣는 형식. */
typedef union kanyptr
{
	kbool*				b;
	kcham*				m;
	kint*				i;
	kuint*				u;
	kfloat*				f;

	kchar*				s;
	kwchar*				w;
	kpointer			p;
	kconstpointer		cp;
	kfunc				func;

	ksbyte*				i8;
	kshort*				i16;
	kint*				i32;
	klong*				i64;

	kbyte*				u8;
	kushort*			u16;
	kuint*				u32;
	kulong*				u64;

	kdouble*			dbl;
} kanyptr;

/** 아무 콜백이나 넣는 형식. */
typedef struct kanycb
{
	kfunc				func;
	kpointer			data;
} kanycb;


//////////////////////////////////////////////////////////////////////////
// endian
#define K_ENDIAN_SWAP_USHORT(n)\
	((kushort)( \
	(kushort)((kushort)(n)>>8) | \
	(kushort)((kushort)(n)<<8) ))
#define K_ENDIAN_SWAP_UINT(n)\
	((kuint)( \
	(((kuint)(n)&(kuint)0x000000FFU)<<24) | \
	(((kuint)(n)&(kuint)0x0000FF00U)<< 8) | \
	(((kuint)(n)&(kuint)0x00FF0000U)>> 8) | \
	(((kuint)(n)&(kuint)0xFF000000U)>>24) ))
#define K_ENDIAN_SWAP_ULONG(n)\
	((kulong)( \
	(((kulong)(n)&(kulong)K_CONST_LONG(0x00000000000000FF))<<56) | \
	(((kulong)(n)&(kulong)K_CONST_LONG(0x000000000000FF00))<<40) | \
	(((kulong)(n)&(kulong)K_CONST_LONG(0x0000000000FF0000))<<24) | \
	(((kulong)(n)&(kulong)K_CONST_LONG(0x00000000FF000000))<< 8) | \
	(((kulong)(n)&(kulong)K_CONST_LONG(0x000000FF00000000))>> 8) | \
	(((kulong)(n)&(kulong)K_CONST_LONG(0x0000FF0000000000))>>24) | \
	(((kulong)(n)&(kulong)K_CONST_LONG(0x00FF000000000000))>>40) | \
	(((kulong)(n)&(kulong)K_CONST_LONG(0xFF00000000000000))>>56) ))


//////////////////////////////////////////////////////////////////////////
// validate
#define k_return_if_fail(x)				K_STMT_BEGIN{ if (!(x)) return; }K_STMT_END
#define k_return_if_ok(x)				K_STMT_BEGIN{ if ((x)) return; }K_STMT_END
#define k_return_value_if_fail(x,r)		K_STMT_BEGIN{ if (!(x)) return (r); }K_STMT_END
#define k_return_value_if_ok(x,r)		K_STMT_BEGIN{ if ((x)) return (r); }K_STMT_END

#define k_goto_if_fail(x,lbl)			K_STMT_BEGIN{ if (!(x)) goto lbl; }K_STMT_END
#define k_goto_if_ok(x,lbl)				K_STMT_BEGIN{ if ((x)) goto lbl; }K_STMT_END


//////////////////////////////////////////////////////////////////////////
// noop
#if !_SB_CPP_ || !_MSC_VER
#define __noop(...)						((void)0)
#endif


//////////////////////////////////////////////////////////////////////////
// standard definition
#ifndef NULL
#ifdef __cplusplus
#if _SB_CPP11_
#define NULL	nullptr
#else
#define NULL    0
#endif
#else
#define NULL    ((kpointer)0)
#endif
#endif

#ifndef FALSE
#define FALSE               0
#endif

#ifndef TRUE
#define TRUE                1
#endif

#endif	// __SBDEF_H__
